package immutablecollections;

import java.io.*;

/**
 * An `ImMaybe` is a wrapper around a value that might be missing.
 * 
 * You can test if there is a value using {@link #hasValue}.
 * 
 * If you try to get the value from an `ImMaybe` and it is missing, it will throw an exception.
 */
class ImMaybe<T> implements Serializable
{
    final private static ImMaybe<?> nothing = new ImMaybe<Object>(null);

    // The thing I am wrapping
    final private T value;

    private ImMaybe(T value)
    {
        this.value = value;
    }

    /**
     * Create a Maybe with a missing value.
     */
    @SuppressWarnings("unchecked")
    public static <A> ImMaybe<A> nothing()
    {
        return (ImMaybe<A>) nothing;
    }

    /**
     * Create an `ImMaybe` with the value `value`.
     * 
     * @throws MaybeCannotHaveANullValueException if `value` is `null`.
     */
    public static <T> ImMaybe<T> with(T value)
    {
        if (value == null)
        {
            throw new MaybeCannotHaveANullValueException();
        }

        return new ImMaybe<T>(value);
    }

    /**
     * Get the value from `this`.
     * 
     * @throws NothingThereException if the value is missing
     */
    public T getValue()
    {
        if (value == null)
            throw new NothingThereException("Maybe contains nothing");
        else
            return value;
    }

    /**
     * `true` if `this` has a value, `false` if it is missing.
     */
    public boolean hasValue()
    {
        return this != nothing;
    }
}
